using MEC;
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace hole.battleroyalegame
{
	public class GameManager : BaseGameManager
	{
		[Serializable]
		public class EditorReferences
		{
			public Hole holePrefab;
		}

		public static GameManager InstanceMode = null;

		public const float GAME_KILL_COOLDOWN = 5f;

		private static readonly int[] XP_TABLE = new int[22]
		{
			0,
			10,
			17,
			24,
			31,
			38,
			45,
			52,
			59,
			66,
			73,
			80,
			87,
			94,
			101,
			108,
			115,
			122,
			129,
			136,
			-1,
			-1
		};

		private static readonly int[] POINTS_PER_SIZE_TABLE = new int[21]
		{
			0,
			1,
			2,
			3,
			4,
			5,
			6,
			7,
			8,
			9,
			10,
			11,
			12,
			13,
			14,
			16,
			18,
			20,
			23,
			28,
			30
		};

		public static readonly int[] STAR_REWARD_TABLE = new int[11]
		{
			30,
			20,
			15,
			10,
			8,
			6,
			4,
			3,
			2,
			1,
			0
		};

		[SerializeField]
		public EditorReferences references = new EditorReferences();

		private Map _currentMap;

		private float _lastKillTime;

		private int _killCount;

		private int _consecutiveKillCount;

		protected override void Awake()
		{
			base.Awake();
			InstanceMode = this;
			if (App.Instance == null)
			{
				SceneManager.LoadScene("Home");
			}
		}

		private void Start()
		{
			GameInit();
		}

		public override void GameInit()
		{
			base.GameInit();
			UIManager.Instance.LoadingComponent.SetTips(GetRandomTips());
			UIManager.Instance.LoadingComponent.SetLoadingImage(MapManager.Instance.CurrentMap.loadingSprite);
			UIManager.Instance.LoadingComponent.SetModeDescription(GameModeManager.Instance.CurrentMode.loadingTitle, GameModeManager.Instance.CurrentMode.loadingDescription);
			UIManager.Instance.OnGameInit();
			UIManager.Instance.KillCounterComponent.SetCount(_killCount);
			Timing.RunCoroutine(LoadGameCoroutine());
		}

		public void CountdownStart()
		{
			UIManager.Instance.OnGameStart();
			Timing.RunCoroutine(CountdownCoroutine().CancelWith(base.gameObject), Segment.LateUpdate);
		}

		public override void GameStart()
		{
			_hasGameStarted = true;
			foreach (Hole currentHole in _currentHoles)
			{
				currentHole.GetComponent<HoleController>().CanMove = true;
			}
			UIManager.Instance.KillCounterComponent.gameObject.SetActive(value: true);
			UIManager.Instance.RankingComponent.gameObject.SetActive(value: true);
			UIManager.Instance.PlayerCounterComponent.gameObject.SetActive(value: true);
			UIManager.Instance.PlayerCounterComponent.SetCount(_currentHoles.Count);
			Timing.RunCoroutine(RankingCoroutine().CancelWith(base.gameObject), Segment.LateUpdate);
		}

		public override void GameEnd()
		{
			base.GameEnd();
			_hasGameEnded = true;
			UIManager.Instance.OnGameEnd();
			CheckEndGameAchievements();
			VoodooServiceLocator.Analytics.GameEnd(_currentHole.Points);
			VoodooServiceLocator.Analytics.LogSkinUsed(_currentHole.CurrentSkinParameters.skinIndex);
			//if (PlayerData.Instance.Vibrations)
			//{
			//	VibrationUtils.StrongVibrate();
			//}
		}

		public override void RegisterFallingObject(FallingObject fo)
		{
			FallingObjectBehaviour fallingObjectBehaviour = null;
			fallingObjectBehaviour = ((!fo.PooledObject) ? ((FallingObjectBehaviour)fo.gameObject.AddComponent<RespawnableFallingObject>()) : ((FallingObjectBehaviour)fo.gameObject.AddComponent<DeactivableFallingObject>()));
			fallingObjectBehaviour.SetGameManager(this);
			fallingObjectBehaviour.SetFallingObject(fo);
			_currentFallingObjects.Add(fallingObjectBehaviour);
		}

		public override void UnregisterFallingObject(FallingObject fo)
		{
			FallingObjectBehaviour component = fo.GetComponent<FallingObjectBehaviour>();
			if ((bool)component)
			{
				_currentFallingObjects.Remove(component);
			}
		}

		private IEnumerator<float> LoadGameCoroutine()
		{
			string sceneName = MapManager.Instance.CurrentMap.gameScene;
			AsyncOperation async = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
			while (!async.isDone)
			{
				UIManager.Instance.LoadingComponent.UpdateLoading(async.progress * 0.8f);
				yield return Timing.WaitForSeconds(0.2f);
			}
			_hasGameLoaded = true;
			UIManager.Instance.LoadingComponent.UpdateLoading(0.9f);
			yield return Timing.WaitForSeconds(1f);
			_currentMap = UnityEngine.Object.FindObjectOfType<Map>();
			_currentMap.Rotate(90 * UnityEngine.Random.Range(0, 4));
			List<Transform> spawnPoints = new List<Transform>(_currentMap.GetSpawnPoints(UnityEngine.Random.Range(0, _currentMap.spawnPoints.Length)));
			spawnPoints.Shuffle_Fisher_Yates();
			int spawnIndex2 = 0;
			Hole h2 = UnityEngine.Object.Instantiate(references.holePrefab, Vector3.zero, Quaternion.identity);
			h2.gameObject.name = "Player Local";
			h2.gameObject.AddComponent<HoleJoystickController>();
			Transform transform = h2.transform;
			List<Transform> list = spawnPoints;
			int index;
			spawnIndex2 = (index = spawnIndex2) + 1;
			transform.position = list[index].position;
			h2.PlayerId = 0;
			h2.IsLocalPlayer = true;
			h2.SetPseudo(PlayerData.Instance.Pseudo);
			h2.SetRank(RankManager.Instance.CachedRank);
			h2.SetSkin(SkinManager.Instance.GetSkinWithIndex(App.Instance.currentSkinIndex));
			h2.SetLevel((!App.Instance.enableBigStart) ? 1 : 2);
			h2.SetHoleLayerIndex(6);
			h2.ShowCrown(s: false);
			h2.OnLevelChanged.AddListener(OnHoleLevelUp);
			_currentHole = h2;
			_currentHoles.Add(h2);
			_currentHoleDictionary.Add(0, h2);
			CameraManager.Instance.SetTarget(h2.transform);
			TransparencyManager.Instance.SetTarget(h2.transform);
			List<SkinParameters> botSkins = new List<SkinParameters>(SkinManager.Instance.Skins);
			botSkins.RemoveAll((SkinParameters s) => !s.isAvailableForBots || s.skinIndex == App.Instance.currentSkinIndex);
			botSkins.Shuffle_Fisher_Yates();
			string[] array = new string[0];
            string[] names =StringDatabase.LIST_NAME_CHINESE.Split(',');
            //string[] names = (!(LocalizationManager.GetLanguage() == "Chinese")) ? StringDatabase.LIST_NAME.Split(',') : $"{StringDatabase.LIST_NAME},{StringDatabase.LIST_NAME_CHINESE}".Split(',');
            for (int i = 0; i < 9; i++)
			{
				float value = UnityEngine.Random.value;
				int rank = (_currentHole.Rank != 0) ? UnityEngine.Random.Range(0, RankManager.Instance.references.ranks.Length) : UnityEngine.Random.Range(0, RankManager.Instance.references.ranks.Length / 2);
				h2 = UnityEngine.Object.Instantiate(references.holePrefab, new Vector3(UnityEngine.Random.Range(-5, 5), 0f, UnityEngine.Random.Range(-5, 5)), Quaternion.identity);
				h2.gameObject.name = $"Bot {i}";
				Transform transform2 = h2.transform;
				List<Transform> list2 = spawnPoints;
				spawnIndex2 = (index = spawnIndex2) + 1;
				transform2.position = list2[index].position;
				h2.PlayerId = i + 1;
				h2.gameObject.AddComponent<BotBattleRoyale>();
				h2.SetSkin(botSkins[i]);
				h2.SetLevel(1);
				h2.SetHoleLayerIndex(i % 6);
				h2.SetPseudo(names[UnityEngine.Random.Range(0, names.Length)]);
				h2.SetRank(rank);
				h2.ShowCrown(s: false);
				_currentHoles.Add(h2);
				_currentHoleDictionary.Add(i + 1, h2);
				UIManager.Instance.IndicatorsComponent.AddIndicator(_currentHole.transform, h2);
			}
			UIManager.Instance.LoadingComponent.UpdateLoading(1f);
			yield return Timing.WaitForSeconds(1f);
			CountdownStart();
		}

		private IEnumerator<float> CountdownCoroutine()
		{
			int countdown = 3;
			UIManager.Instance.CountdownComponent.Show();
			UIManager.Instance.CountdownComponent.SetCountdown(countdown);
			while (countdown > 0)
			{
				yield return Timing.WaitForSeconds(1f);
				countdown--;
				UIManager.Instance.CountdownComponent.SetCountdown(countdown);
			}
			GameStart();
			yield return Timing.WaitForSeconds(0.5f);
			UIManager.Instance.CountdownComponent.Hide();
		}

		public IEnumerator<float> RankingCoroutine()
		{
			while (!_hasGameEnded)
			{
				UpdateRanking();
				yield return Timing.WaitForSeconds(0.2f);
			}
		}

		public override void ProcessCapture(FallingObjectBehaviour fob, int holeId)
		{
			if (_hasGameEnded || holeId == -1)
			{
				return;
			}
			Hole hole = _currentHoleDictionary[holeId];
			int level = hole.Level;
			hole.AddXp(POINTS_PER_SIZE_TABLE[fob.FallingObject.Points], XP_TABLE[hole.Level], XP_TABLE[hole.Level + 1]);
			hole.AddPoints(POINTS_PER_SIZE_TABLE[fob.FallingObject.Points]);
			if (holeId == _currentHole.PlayerId)
			{
				UIManager.Instance.FloatingTextComponent.ShowText($"+{POINTS_PER_SIZE_TABLE[fob.FallingObject.Points]}");
				FallingObject.FallingObjectType objectType = fob.FallingObject.ObjectType;
				if (objectType == FallingObject.FallingObjectType.Animal)
				{
					CheckAnimalsAchievement(fob.FallingObject.ObjectTags[0], fob.FallingObject.ObjectTags[1]);
				}
			}
			if (level != hole.Level)
			{
				CheckGameOver();
			}
		}

		public override void ProcessKill(int killerHoleId, int victimHoleId)
		{
			if (_hasGameEnded)
			{
				return;
			}
			Hole hole = _currentHoleDictionary[killerHoleId];
			Hole hole2 = _currentHoleDictionary[victimHoleId];
			if (killerHoleId == _currentHole.PlayerId)
			{
				_consecutiveKillCount++;
				UIManager.Instance.KillCounterComponent.SetCount(_consecutiveKillCount);
				if (Time.time - _lastKillTime > 5f)
				{
					_killCount++;
				}
				else
				{
					_killCount = 1;
				}
				_lastKillTime = Time.time;
				UIManager.Instance.FloatingTextComponent.ShowKill(hole2.CurrentSkinParameters.mainColor, _killCount, 5 * hole2.Level);
			}
			if (victimHoleId == _currentHole.PlayerId)
			{
				UIManager.Instance.GameOverComponent.SetKiller(hole);
			}
			hole.AddPoints(5 * hole2.Level);
			hole.AddXp(5 * hole2.Level, XP_TABLE[hole.Level], XP_TABLE[hole.Level + 1]);
			hole2.GetComponent<HoleController>().CanMove = false;
			hole2.Die(respawn: false);
			_currentHoles.Remove(hole2);
			UIManager.Instance.PlayerCounterComponent.SetCount(_currentHoles.Count);
			CheckGameOver();
		}

		private void CheckGameOver()
		{
			bool flag = false;
			foreach (Hole currentHole in _currentHoles)
			{
				if (currentHole.IsLocalPlayer)
				{
					flag = true;
					break;
				}
			}
			if (!flag)
			{
				UIManager.Instance.GameOverComponent.SetVictory(b: false);
				UIManager.Instance.GameOverComponent.SetRank(_currentHoles.Count);
				_reward = STAR_REWARD_TABLE[Mathf.Clamp(_currentHoles.Count, 0, STAR_REWARD_TABLE.Length - 1)];
				RankManager.Instance.AddXpReward(_reward);
				GameEnd();
				return;
			}
			if (flag && _currentHoles.Count == 1)
			{
				UIManager.Instance.GameOverComponent.SetKiller(null);
				UIManager.Instance.GameOverComponent.SetVictory(b: true);
				UIManager.Instance.GameOverComponent.SetRank(0);
				_reward = STAR_REWARD_TABLE[0];
				RankManager.Instance.AddXpReward(_reward);
				GameEnd();
				return;
			}
			bool flag2 = true;
			foreach (Hole currentHole2 in _currentHoles)
			{
				if (currentHole2.Level < 20)
				{
					flag2 = false;
					break;
				}
			}
			if (flag2)
			{
				UIManager.Instance.GameOverComponent.SetKiller(null);
				UIManager.Instance.GameOverComponent.SetVictory(b: true);
				UIManager.Instance.GameOverComponent.SetRank(0);
				_reward = STAR_REWARD_TABLE[0];
				RankManager.Instance.AddXpReward(_reward);
				GameEnd();
			}
		}

		public void UpdateRanking()
		{
			List<Hole> list = new List<Hole>(_currentHoles);
			list.Sort((Hole h1, Hole h2) => (h2.Level - h1.Level) * 10000 + (h2.Points - h1.Points));
			float num = list[0].Points;
			if (num < 1f)
			{
				Hole[] array = list.ToArray();
				foreach (Hole hole in array)
				{
					if (hole.IsLocalPlayer)
					{
						list.Remove(hole);
						list.Insert(0, hole);
						break;
					}
				}
				for (int j = 0; j < _currentHoles.Count; j++)
				{
					list[j].ShowCrown(s: false);
				}
			}
			else
			{
				for (int k = 0; k < _currentHoles.Count; k++)
				{
					list[k].ShowCrown(k == 0);
				}
			}
			UIManager.Instance.RankingComponent.UpdateRanking(list);
		}

		public void OnHoleLevelUp(int level)
		{
			float t = (float)(level - 1) / 19f;
			CameraManager.Instance.SetDistance(Mathf.Lerp(13f, 175f, t), Mathf.Lerp(16f, 130f, t));
			UIManager.Instance.FloatingTextComponent.ShowLevelUp(_currentHole.CurrentSkinParameters.mainColor, level == 20);
		}

		public int GetStarRewardByRank(int rank)
		{
			rank = Mathf.Clamp(rank, 0, STAR_REWARD_TABLE.Length - 1);
			return STAR_REWARD_TABLE[rank];
		}
	}
}
